/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server_client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Queue;
import javax.net.ssl.*;

/**
 * Klasa "Server" odpowiada utworzenie procesu serwera.
 * @author Piotr Jasiak, Szymon Wawrzyniak, Artur Angiel
 */
public class Server {

    private ObjectInputStream in;
    private ObjectOutputStream out;
    private Object receivedObject;
    private SSLServerSocketFactory sslserversocketfactory;
    private SSLServerSocket sslserversocket;
    private ArrayList<Thread> threads;
    private ArrayList<SSLSocket> sockets;
    private Thread serverInstance;
    private Queue<Object> receivedObjects;

    /**
     * Pusty konstruktor
     * @param port Numer portu, na którym serwer będzie nasłuchiwał.
     * @throws IOException
     */
    public Server(int port) throws IOException {


	System.setProperty("javax.net.ssl.keyStore", "src/server_client/certyfikat");
	System.setProperty("javax.net.ssl.keyStorePassword", "inzopr");

	sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
	sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port);
	threads = new ArrayList<Thread>();
	sockets = new ArrayList<SSLSocket>();
	
	serverInstance = new Thread(new ServerInstance());
	serverInstance.start();
    }

    public ArrayList<SSLSocket> getSockets() {
	return this.sockets;
    }

    /**
     * Metoda "send" wysyła obiekt do podanego klienta.
     * @param obj Obiekt do wysłania.
     * @param socket Socket klienta.
     * @return 0 - obiekt wysłany; -1 - błąd wejścia/wyjścia.
     */
    public int send(Object obj, SSLSocket socket) {
	try {
	    
	    out.writeObject(obj);
	    out.flush();
	    out.reset();
	} catch (IOException ex) {
	    return -1;
	}
	return 0;
    }

    /**
     * Klasa "ClientWorker" reprezentuje pojedynczy wątek połączenia.
     * Implementuje interfesj "Runnable".
     */
    class ClientWorker implements Runnable {

	private SSLSocket client;

	/**
	 * Konstruktor przypisuje konkretnego klienta do wątku.
	 * @param client Identyfikator podłączonego klienta.
	 */
	public ClientWorker(SSLSocket client) {
	    this.client = client;
	}

	/**
	 * Metoda "run" jest zaimplementowana z interfejsu "Runnable".
	 */
	public void run() {
	    try {
		in = new ObjectInputStream(new BufferedInputStream(client.getInputStream()));
	    } catch (IOException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    }
	    try {


		while ((receivedObject =  in.readObject()) != null) {
//		    System.out.println(receivedObject.napis););
		}

	    } catch (IOException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    } catch (ClassNotFoundException ex) {
		//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
	    }
	    this.stop();
	}

	public void stop() {
	    threads.remove(this);
	    System.out.println("stop" + this.client.getSession());

	}
    }
       public Object getFromQueue() {
        Object tmp; 
        tmp = receivedObjects.peek();
        receivedObjects.poll();
        return tmp;
}

    /**
     * Metoda "receive" służy do zwrócenia odebranego objektu
     * @return Object Odebrany objekt
     */
    public void receive() {
          receivedObjects.add(receivedObject);
    }
    
    class ServerInstance implements Runnable{

	@Override
	public void run() {
	    while (true) {
	    try {
		//server.accept returns a client connection
		sockets.add((SSLSocket) sslserversocket.accept());
		System.out.println("nowe połączenie: " + sockets.get(sockets.size() - 1).getSession());
		threads.add(new Thread(new ClientWorker(sockets.get(sockets.size() - 1))));
		threads.get(threads.size() - 1).start();
		
		out = new ObjectOutputStream(new BufferedOutputStream(sockets.get(sockets.size() - 1).getOutputStream()));
	    } catch (IOException e) {
		System.out.println("Accept failed: 4444");
		System.exit(-1);
	    }
	}
	}
	
    }
}
